﻿using System;
using System.Collections.Generic;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using Autodesk.Revit.UI;
using YArchitech.Revit;
using YJKArchMethodLibrary.Utils;

namespace WallCreateAndEdit.WallModule.EditWall
{
	public class WallSearchManager
	{
		public WallSearchManager(ExternalCommandData cmdData)
		{
			this.m_Revit = cmdData;
		}

		public bool Search(bool searchOutWall, ref List<WallData> wallDataList)
		{
			List<RoomData> roomDataList = new List<RoomData>();
			if (!this.GetRoomDataInfos(ref roomDataList))
			{
				return false;
			}
			List<WallData> allWallDataList = new List<WallData>();
			return this.GetWallDataInfos(ref allWallDataList) && this.Search(roomDataList, allWallDataList, searchOutWall, ref wallDataList);
		}

		private bool GetRoomDataInfos(ref List<RoomData> roomDataList)
		{
			Transaction transaction = null;
			bool result;
			try
			{
				Document document = this.m_Revit.Application.ActiveUIDocument.Document;
				transaction = new Transaction(document);
				transaction.Start("get room data");
				this.RemoveRooms();
				roomDataList = this.Create2ndGetRoomDataInfos();
				if (transaction != null && transaction.HasStarted() && !transaction.HasEnded())
				{
					transaction.RollBack();
				}
				result = true;
			}
			catch (Exception)
			{
				if (transaction != null && transaction.HasStarted() && !transaction.HasEnded())
				{
					transaction.RollBack();
				}
				result = false;
			}
			return result;
		}

		private void RemoveRooms()
		{
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.m_Revit.Application.ActiveUIDocument.Document, this.m_Revit.Application.ActiveUIDocument.ActiveView.Id).OfClass(typeof(SpatialElement));
			List<ElementId> list = new List<ElementId>();
			foreach (Element element in filteredElementCollector)
			{
				SpatialElement spatialElement = (SpatialElement)element;
				Room room = spatialElement as Room;
				if (room != null)
				{
					list.Add(room.Id);
				}
			}
			this.m_Revit.Application.ActiveUIDocument.Document.Delete(list);
		}

		private List<RoomData> Create2ndGetRoomDataInfos()
		{
			Document document = this.m_Revit.Application.ActiveUIDocument.Document;
			Level genLevel = this.m_Revit.Application.ActiveUIDocument.ActiveView.GenLevel;
			List<RoomData> list = new List<RoomData>();
			double num = AssistFunc.mmToFeet(10.0);
			num *= num;
			SpatialElementBoundaryOptions spatialElementBoundaryOptions = new SpatialElementBoundaryOptions();
			PlanTopology planTopology = document.get_PlanTopology(genLevel);
			foreach (object obj in planTopology.Circuits)
			{
				PlanCircuit planCircuit = (PlanCircuit)obj;
				if (!planCircuit.IsRoomLocated && !Geometry.LessThan(planCircuit.Area, num))
				{
					Room room = document.Create.NewRoom(null, planCircuit);
					List<RoomData.BoundingSegment> list2 = new List<RoomData.BoundingSegment>();
					IList<IList<BoundarySegment>> boundarySegments = room.GetBoundarySegments(spatialElementBoundaryOptions);
					foreach (IList<BoundarySegment> list3 in boundarySegments)
					{
						foreach (BoundarySegment segment in list3)
						{
							Element element = segment.GetElement(document);
							if (element != null && !(element.GetType() != typeof(Wall)))
							{
								Curve curve = segment.GetCurve();
								EdgeInfo curve2 = new EdgeInfo(curve, false);
								RoomData.BoundingSegment item = new RoomData.BoundingSegment(curve2, element.Id);
								list2.Add(item);
							}
						}
					}
					RoomData item2 = new RoomData(list2);
					list.Add(item2);
				}
			}
			return list;
		}

		private bool GetWallDataInfos(ref List<WallData> wallDataList)
		{
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.m_Revit.Application.ActiveUIDocument.Document, this.m_Revit.Application.ActiveUIDocument.ActiveView.Id).OfClass(typeof(Wall)).OfCategory(BuiltInCategory.OST_Walls);
			foreach (Element element in filteredElementCollector)
			{
				Wall wall = element as Wall;
				if (wall != null)
				{
					WallData wallData = this.GetWallData(wall);
					wallDataList.Add(wallData);
				}
			}
			return true;
		}

		private WallData GetWallData(Wall wall)
		{
			double num = wall.Width / 2.0;
			LocationCurve locationCurve = wall.Location as LocationCurve;
			Curve curve = locationCurve.Curve;
			if (curve.GetType() == typeof(Line))
			{
				Line line = curve as Line;
				Line curve2 = Geometry.OffsetLine(line, num);
				EdgeInfo positiveLine = new EdgeInfo(curve2, false);
				Line curve3 = Geometry.OffsetLine(line, -num);
				EdgeInfo negativeLine = new EdgeInfo(curve3, false);
				EdgeInfo centerLine = new EdgeInfo(line, false);
				return new WallData(positiveLine, negativeLine, centerLine, wall.Id);
			}
			if (curve.GetType() == typeof(Arc))
			{
				Arc arc = curve as Arc;
				Arc curve4 = Geometry.OffsetArc(this.m_Revit.Application.Application, arc, num);
				EdgeInfo positiveLine2 = new EdgeInfo(curve4, false);
				Arc curve5 = Geometry.OffsetArc(this.m_Revit.Application.Application, arc, -num);
				EdgeInfo negativeLine2 = new EdgeInfo(curve5, false);
				EdgeInfo centerLine2 = new EdgeInfo(arc, false);
				return new WallData(positiveLine2, negativeLine2, centerLine2, wall.Id);
			}
			return null;
		}

		private bool Search(List<RoomData> roomDataList, List<WallData> allWallDataList, bool searchOutWall, ref List<WallData> wallDataList)
		{
			foreach (RoomData roomData in roomDataList)
			{
				List<RoomData.BoundingSegment> wallSegmentList = roomData.WallSegmentList;
				foreach (RoomData.BoundingSegment segment in wallSegmentList)
				{
					for (int i = 0; i < allWallDataList.Count; i++)
					{
						WallData wallData = allWallDataList[i];
						this.Search(segment, ref wallData);
						allWallDataList[i].FindedPositive = wallData.FindedPositive;
						allWallDataList[i].FindedNegative = wallData.FindedNegative;
					}
				}
			}
			foreach (WallData wallData2 in allWallDataList)
			{
				WallData.OutWallOrientations outWallOrientations = WallData.OutWallOrientations.OWO_Two_Sided;
				if (searchOutWall)
				{
					if (wallData2.IsOutWall(ref outWallOrientations))
					{
						wallDataList.Add(wallData2);
					}
				}
				else if (!wallData2.IsOutWall(ref outWallOrientations) && outWallOrientations != WallData.OutWallOrientations.OWO_None)
				{
					wallDataList.Add(wallData2);
				}
			}
			return true;
		}

		private void Search(RoomData.BoundingSegment segment, ref WallData wallData)
		{
			if (segment.WallId.IntegerValue != wallData.Id.IntegerValue)
			{
				return;
			}
			double tolerance = 0.01;
			if (!segment.Curve.IsArc && !wallData.PositiveLine.IsArc)
			{
				EdgeInfo curve = segment.Curve;
				EdgeInfo positiveLine = wallData.PositiveLine;
				XYZ xyz = null;
				XYZ xyz2 = null;
				Geometry.OverlapType overlapType = Geometry.IsOverlapOfTwoLine(this.Point2d(curve.StartPoint), this.Point2d(curve.EndPoint), this.Point2d(positiveLine.StartPoint), this.Point2d(positiveLine.EndPoint), ref xyz, ref xyz2, true, tolerance);
				if (overlapType != Geometry.OverlapType._OT_None && overlapType != Geometry.OverlapType._OT_Linked)
				{
					wallData.FindedPositive = true;
				}
				EdgeInfo negativeLine = wallData.NegativeLine;
				overlapType = Geometry.IsOverlapOfTwoLine(this.Point2d(curve.StartPoint), this.Point2d(curve.EndPoint), this.Point2d(negativeLine.StartPoint), this.Point2d(negativeLine.EndPoint), ref xyz, ref xyz2, true, tolerance);
				if (overlapType != Geometry.OverlapType._OT_None && overlapType != Geometry.OverlapType._OT_Linked)
				{
					wallData.FindedNegative = true;
					return;
				}
			}
			else if (segment.Curve.IsArc && wallData.PositiveLine.IsArc)
			{
				EdgeInfo curve2 = segment.Curve;
				XYZ xyz3 = curve2.StartPoint;
				XYZ xyz4 = curve2.EndPoint;
				XYZ pt = null;
				Geometry.GetCenterWithBulge(xyz3, xyz4, curve2.Bulge, ref pt);
				EdgeInfo positiveLine2 = wallData.PositiveLine;
				if (Geometry.LessThan(curve2.Bulge, 0.0))
				{
					if (Geometry.GreaterThan(positiveLine2.Bulge, 0.0))
					{
						xyz3 = curve2.EndPoint;
						xyz4 = curve2.StartPoint;
					}
				}
				else if (Geometry.LessThan(positiveLine2.Bulge, 0.0))
				{
					xyz3 = curve2.EndPoint;
					xyz4 = curve2.StartPoint;
				}
				XYZ pt2 = null;
				Geometry.GetCenterWithBulge(positiveLine2.StartPoint, positiveLine2.EndPoint, positiveLine2.Bulge, ref pt2);
				XYZ xyz5 = null;
				XYZ xyz6 = null;
				Geometry.OverlapType overlapType2 = Geometry.IsOverlapOfTwoArc(this.Point2d(xyz3), this.Point2d(xyz4), this.Point2d(pt), this.Point2d(positiveLine2.StartPoint), this.Point2d(positiveLine2.EndPoint), this.Point2d(pt2), ref xyz5, ref xyz6, 1E-09);
				if (overlapType2 != Geometry.OverlapType._OT_None && overlapType2 != Geometry.OverlapType._OT_Linked)
				{
					wallData.FindedPositive = true;
				}
				EdgeInfo negativeLine2 = wallData.NegativeLine;
				overlapType2 = Geometry.IsOverlapOfTwoArc(this.Point2d(xyz3), this.Point2d(xyz4), this.Point2d(pt), this.Point2d(negativeLine2.StartPoint), this.Point2d(negativeLine2.EndPoint), this.Point2d(pt2), ref xyz5, ref xyz6, 1E-09);
				if (overlapType2 != Geometry.OverlapType._OT_None && overlapType2 != Geometry.OverlapType._OT_Linked)
				{
					wallData.FindedNegative = true;
				}
			}
		}

		private XYZ Point2d(XYZ pt)
		{
			return new XYZ(pt.X, pt.Y, 0.0);
		}

		private ExternalCommandData m_Revit;
	}
}
